/*
===========================================================================

Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.

This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").

Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

===========================================================================
*/

#include "Precompiled.h"
#include "globaldata.h"


#include "i_system.h"
#include "r_local.h"

#include "doomdef.h"
#include "doomdata.h"

#include "m_bbox.h"
#include "m_swap.h"

#include "v_video.h"


// Each screen is [ORIGINAL_WIDTH*ORIGINALHEIGHT];




// Now where did these came from?
const byte gammatable[5][256] =
{
	{
		1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
		17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
		33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
		49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
		65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
		81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
		97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
		113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
		128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
		144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
		160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
		176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
		192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
		208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
		224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
		240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
	},

	{
		2, 4, 5, 7, 8, 10, 11, 12, 14, 15, 16, 18, 19, 20, 21, 23, 24, 25, 26, 27, 29, 30, 31,
		32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 55,
		56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77,
		78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
		99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
		115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 129,
		130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145,
		146, 147, 148, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
		161, 162, 163, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
		175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 186, 187, 188, 189,
		190, 191, 192, 193, 194, 195, 196, 196, 197, 198, 199, 200, 201, 202, 203, 204,
		205, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 214, 215, 216, 217, 218,
		219, 220, 221, 222, 222, 223, 224, 225, 226, 227, 228, 229, 230, 230, 231, 232,
		233, 234, 235, 236, 237, 237, 238, 239, 240, 241, 242, 243, 244, 245, 245, 246,
		247, 248, 249, 250, 251, 252, 252, 253, 254, 255
	},

	{
		4, 7, 9, 11, 13, 15, 17, 19, 21, 22, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 40, 42,
		43, 45, 46, 47, 48, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69,
		70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
		94, 95, 96, 97, 98, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
		113, 114, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
		129, 130, 131, 132, 133, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
		144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 153, 154, 155, 156, 157, 158, 159,
		160, 160, 161, 162, 163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 172, 172, 173,
		174, 175, 176, 177, 178, 178, 179, 180, 181, 182, 183, 183, 184, 185, 186, 187, 188,
		188, 189, 190, 191, 192, 193, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 201,
		202, 203, 204, 205, 206, 206, 207, 208, 209, 210, 210, 211, 212, 213, 213, 214, 215,
		216, 217, 217, 218, 219, 220, 221, 221, 222, 223, 224, 224, 225, 226, 227, 228, 228,
		229, 230, 231, 231, 232, 233, 234, 235, 235, 236, 237, 238, 238, 239, 240, 241, 241,
		242, 243, 244, 244, 245, 246, 247, 247, 248, 249, 250, 251, 251, 252, 253, 254, 254,
		255
	},

	{
		8, 12, 16, 19, 22, 24, 27, 29, 31, 34, 36, 38, 40, 41, 43, 45, 47, 49, 50, 52, 53, 55,
		57, 58, 60, 61, 63, 64, 65, 67, 68, 70, 71, 72, 74, 75, 76, 77, 79, 80, 81, 82, 84, 85,
		86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
		108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
		125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140,
		141, 142, 143, 143, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155,
		155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 165, 165, 166, 167, 168, 169,
		169, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 179, 180, 180, 181, 182,
		183, 183, 184, 185, 186, 186, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 195,
		195, 196, 197, 197, 198, 199, 200, 200, 201, 202, 202, 203, 204, 205, 205, 206, 207,
		207, 208, 209, 210, 210, 211, 212, 212, 213, 214, 214, 215, 216, 216, 217, 218, 219,
		219, 220, 221, 221, 222, 223, 223, 224, 225, 225, 226, 227, 227, 228, 229, 229, 230,
		231, 231, 232, 233, 233, 234, 235, 235, 236, 237, 237, 238, 238, 239, 240, 240, 241,
		242, 242, 243, 244, 244, 245, 246, 246, 247, 247, 248, 249, 249, 250, 251, 251, 252,
		253, 253, 254, 254, 255
	},

	{
		16, 23, 28, 32, 36, 39, 42, 45, 48, 50, 53, 55, 57, 60, 62, 64, 66, 68, 69, 71, 73, 75, 76,
		78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 93, 94, 96, 97, 98, 100, 101, 102, 103, 105, 106,
		107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
		125, 126, 128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
		142, 143, 143, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155,
		156, 157, 158, 159, 159, 160, 161, 162, 163, 163, 164, 165, 166, 166, 167, 168, 169,
		169, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 177, 178, 179, 180, 180, 181,
		182, 182, 183, 184, 184, 185, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
		193, 194, 195, 195, 196, 196, 197, 198, 198, 199, 200, 200, 201, 202, 202, 203, 203,
		204, 205, 205, 206, 207, 207, 208, 208, 209, 210, 210, 211, 211, 212, 213, 213, 214,
		214, 215, 216, 216, 217, 217, 218, 219, 219, 220, 220, 221, 221, 222, 223, 223, 224,
		224, 225, 225, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 232, 232, 233, 233,
		234, 234, 235, 235, 236, 236, 237, 237, 238, 239, 239, 240, 240, 241, 241, 242, 242,
		243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251,
		251, 252, 252, 253, 254, 254, 255, 255
	}
};




//
// V_MarkRect
//
void
V_MarkRect
( int		x,
  int		y,
  int		width,
  int		height )
{
	M_AddToBox( ::g->dirtybox, x, y );
	M_AddToBox( ::g->dirtybox, x + width - 1, y + height - 1 );
}


//
// V_CopyRect
//
void
V_CopyRect
( int		srcx,
  int		srcy,
  int		srcscrn,
  int		width,
  int		height,
  int		destx,
  int		desty,
  int		destscrn )
{
	byte*	src;
	byte*	dest;

#ifdef RANGECHECK
	if( srcx < 0
			|| srcx + width > ORIGINAL_WIDTH
			|| srcy < 0
			|| srcy + height > ORIGINAL_HEIGHT
			|| destx < 0 || destx + width > ORIGINAL_WIDTH
			|| desty < 0
			|| desty + height > ORIGINAL_HEIGHT
			|| ( unsigned )srcscrn > 4
			|| ( unsigned )destscrn > 4 )
	{
		I_Error( "Bad V_CopyRect" );
	}
#endif
	V_MarkRect( destx, desty, width, height );

	// SMF - rewritten for scaling
	srcx *= GLOBAL_IMAGE_SCALER;
	srcy *= GLOBAL_IMAGE_SCALER;
	destx *= GLOBAL_IMAGE_SCALER;
	desty *= GLOBAL_IMAGE_SCALER;
	width *= GLOBAL_IMAGE_SCALER;
	height *= GLOBAL_IMAGE_SCALER;

	src = ::g->screens[srcscrn] + srcy * SCREENWIDTH + srcx;
	dest = ::g->screens[destscrn] + desty * SCREENWIDTH + destx;

	for( ; height > 0 ; height-- )
	{
		memcpy( dest, src, width );
		src += SCREENWIDTH;
		dest += SCREENWIDTH;
	}
}


//
// V_DrawPatch
// Masks a column based masked pic to the screen.
//
void
V_DrawPatch
( int		x,
  int		y,
  int		scrn,
  patch_t*	patch )
{

	int				count;
	int				col;
	postColumn_t*	column;
	byte*			source;
	int				w;

	y -= SHORT( patch->topoffset );
	x -= SHORT( patch->leftoffset );
#ifdef RANGECHECK
	if( x < 0
			|| x + SHORT( patch->width ) > ORIGINAL_WIDTH
			|| y < 0
			|| y + SHORT( patch->height ) > ORIGINAL_HEIGHT
			|| ( unsigned )scrn > 4 )
	{
		I_PrintfE( "Patch at %d,%d exceeds LFB\n", x, y );
		// No I_Error abort - what is up with TNT.WAD?
		I_PrintfE( "V_DrawPatch: bad patch (ignored)\n" );
		return;
	}
#endif

	if( !scrn )
	{
		V_MarkRect( x, y, SHORT( patch->width ), SHORT( patch->height ) );
	}

	col = 0;
	int destx = x;
	int desty = y;

	w = SHORT( patch->width );

	// SMF - rewritten for scaling
	for( ; col < w ; x++, col++ )
	{
		column = ( postColumn_t* )( ( byte* )patch + LONG( patch->columnofs[col] ) );

		destx = x;

		// step through the posts in a column
		while( column->topdelta != 0xff )
		{
			source = ( byte* )column + 3;
			desty = y + column->topdelta;
			count = column->length;

			while( count-- )
			{
				int scaledx, scaledy;
				scaledx = destx * GLOBAL_IMAGE_SCALER;
				scaledy = desty * GLOBAL_IMAGE_SCALER;
				byte src = *source++;

				for( int i = 0; i < GLOBAL_IMAGE_SCALER; i++ )
				{
					for( int j = 0; j < GLOBAL_IMAGE_SCALER; j++ )
					{
						::g->screens[scrn][( scaledx + j ) + ( scaledy + i ) * SCREENWIDTH] = src;
					}
				}

				desty++;
			}

			column = ( postColumn_t* )( ( byte* )column + column->length + 4 );
		}
	}
}

//
// V_DrawPatchFlipped
// Masks a column based masked pic to the screen.
// Flips horizontally, e.g. to mirror face.
//
void
V_DrawPatchFlipped
( int		x,
  int		y,
  int		scrn,
  patch_t*	patch )
{

	int				count;
	int				col;
	postColumn_t*	column;
	byte*			source;
	int				w;

	y -= SHORT( patch->topoffset );
	x -= SHORT( patch->leftoffset );
#ifdef RANGECHECK
	if( x < 0
			|| x + SHORT( patch->width ) > ORIGINAL_WIDTH
			|| y < 0
			|| y + SHORT( patch->height ) > ORIGINAL_HEIGHT
			|| ( unsigned )scrn > 4 )
	{
		I_PrintfE( "Patch origin %d,%d exceeds LFB\n", x, y );
		I_Error( "Bad V_DrawPatch in V_DrawPatchFlipped" );
	}
#endif

	if( !scrn )
	{
		V_MarkRect( x, y, SHORT( patch->width ), SHORT( patch->height ) );
	}

	col = 0;
	int destx = x;
	int desty = y;

	w = SHORT( patch->width );

	for( ; col < w ; x++, col++ )
	{
		column = ( postColumn_t* )( ( byte* )patch + LONG( patch->columnofs[w - 1 - col] ) );

		destx = x;

		// step through the posts in a column
		while( column->topdelta != 0xff )
		{
			source = ( byte* )column + 3;
			desty = y + column->topdelta;
			count = column->length;

			while( count-- )
			{
				int scaledx, scaledy;
				scaledx = destx * GLOBAL_IMAGE_SCALER;
				scaledy = desty * GLOBAL_IMAGE_SCALER;
				byte src = *source++;

				for( int i = 0; i < GLOBAL_IMAGE_SCALER; i++ )
				{
					for( int j = 0; j < GLOBAL_IMAGE_SCALER; j++ )
					{
						::g->screens[scrn][( scaledx + j ) + ( scaledy + i ) * SCREENWIDTH] = src;
					}
				}

				desty++;
			}
			column = ( postColumn_t* )( ( byte* )column + column->length + 4 );
		}
	}
}



//
// V_DrawPatchDirect
// Draws directly to the screen on the pc.
//
void
V_DrawPatchDirect
( int		x,
  int		y,
  int		scrn,
  patch_t*	patch )
{
	V_DrawPatch( x, y, scrn, patch );

	/*
	int		count;
	int		col;
	postColumn_t*	column;
	byte*	desttop;
	byte*	dest;
	byte*	source;
	int		w;

	y -= SHORT(patch->topoffset);
	x -= SHORT(patch->leftoffset);

	#ifdef RANGECHECK
	if (x<0
	||x+SHORT(patch->width) >ORIGINAL_WIDTH
	|| y<0
	|| y+SHORT(patch->height)>ORIGINAL_HEIGHT
	|| (unsigned)scrn>4)
	{
	I_Error ("Bad V_DrawPatchDirect");
	}
	#endif

	//	V_MarkRect (x, y, SHORT(patch->width), SHORT(patch->height));
	desttop = destscreen + y*ORIGINAL_WIDTH/4 + (x>>2);

	w = SHORT(patch->width);
	for ( col = 0 ; col<w ; col++)
	{
	outp (SC_INDEX+1,1<<(x&3));
	column = (postColumn_t *)((byte *)patch + LONG(patch->columnofs[col]));

	// step through the posts in a column

	while (column->topdelta != 0xff )
	{
	    source = (byte *)column + 3;
	    dest = desttop + column->topdelta*ORIGINAL_WIDTH/4;
	    count = column->length;

	    while (count--)
	    {
		*dest = *source++;
		dest += ORIGINAL_WIDTH/4;
	    }
	    column = (postColumn_t *)(  (byte *)column + column->length
				    + 4 );
	}
	if ( ((++x)&3) == 0 )
	    desttop++;	// go to next byte, not next plane
	}*/
}



//
// V_DrawBlock
// Draw a linear block of pixels into the view buffer.
//
void
V_DrawBlock
( int		x,
  int		y,
  int		scrn,
  int		width,
  int		height,
  byte*		src )
{
	byte*	dest;

#ifdef RANGECHECK
	if( x < 0
			|| x + width > SCREENWIDTH
			|| y < 0
			|| y + height > SCREENHEIGHT
			|| ( unsigned )scrn > 4 )
	{
		I_Error( "Bad V_DrawBlock" );
	}
#endif

	V_MarkRect( x, y, width, height );

	dest = ::g->screens[scrn] + y * SCREENWIDTH + x;

	while( height-- )
	{
		memcpy( dest, src, width );
		src += width;
		dest += SCREENWIDTH;
	}
}



//
// V_GetBlock
// Gets a linear block of pixels from the view buffer.
//
void
V_GetBlock
( int		x,
  int		y,
  int		scrn,
  int		width,
  int		height,
  byte*		dest )
{
	byte*	src;

#ifdef RANGECHECK
	if( x < 0
			|| x + width > SCREENWIDTH
			|| y < 0
			|| y + height > SCREENHEIGHT
			|| ( unsigned )scrn > 4 )
	{
		I_Error( "Bad V_DrawBlock" );
	}
#endif

	src = ::g->screens[scrn] + y * SCREENWIDTH + x;

	while( height-- )
	{
		memcpy( dest, src, width );
		src += SCREENWIDTH;
		dest += width;
	}
}




//
// V_Init
//
void V_Init( void )
{
	int		i;
	byte*	base;

	// stick these in low dos memory on PCs

	base = ( byte* )DoomLib::Z_Malloc( SCREENWIDTH * SCREENHEIGHT * 4, PU_STATIC, 0 );

	for( i = 0 ; i < 4 ; i++ )
	{
		::g->screens[i] = base + i * SCREENWIDTH * SCREENHEIGHT;
	}
}

